<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <title>视频语音翻译系统</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
        * { margin:0; padding:0; box-sizing:border-box; font-family: 'Segoe UI', Tahoma, Arial; }
        body { background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); color:#fff; min-height:100vh; padding:20px; }
        .container { max-width: 1400px; margin: 0 auto; }
        header { text-align:center; margin-bottom:30px; padding:20px; background:rgba(0,0,0,0.3); border-radius:15px; backdrop-filter: blur(10px); }
        h1 { font-size:2.2rem; margin-bottom:8px; }
        .subtitle { opacity:0.9; }
        .content { display:grid; grid-template-columns: 1fr 1fr; gap:20px; margin-bottom:30px; }
        @media (max-width: 1024px) { .content { grid-template-columns: 1fr; } }
        .panel { background: rgba(0,0,0,0.4); border-radius: 15px; padding: 20px; backdrop-filter: blur(10px); box-shadow: 0 8px 32px rgba(0,0,0,0.2); }
        .panel h2 { color:#fdbb2d; margin-bottom:12px; border-bottom:2px solid rgba(253,187,45,0.18); padding-bottom:8px; }
        button { padding:10px 14px; border:none; border-radius:6px; background:#fdbb2d; color:#1a2a6c; font-weight:700; cursor:pointer; transition: all .2s; }
        button:hover { background:#ffcc44; transform: translateY(-1px); }
        button:disabled { background:#666; cursor:not-allowed; transform:none; }
        .audio-guide { padding:15px; margin-bottom:16px; border-radius:10px; background: rgba(255,255,255,0.1); line-height:1.6; }
        .audio-guide p { margin:0; }
        .audio-viz-wrap { padding:8px; border:2px solid rgba(255,255,255,0.14); border-radius:10px; background: rgba(0,0,0,0.12); }
        #audioCanvas { width:100%; height:80px; background:#0b0b0b; border-radius:6px; display:block; }
        .controls { display:flex; gap:8px; margin-top:10px; }
        .status { margin-top:12px; padding:10px; border-radius:6px; background: rgba(255,255,255,0.06); min-height:56px; }
        .recording-indicator { display:flex; align-items:center; gap:8px; margin-top:8px; font-size:0.9rem; }
        .pulse { width:10px; height:10px; border-radius:50%; background:#ff4444; animation: pulse 1.5s infinite; }
        @keyframes pulse { 0% { opacity:1 } 50% { opacity:.3 } 100% { opacity:1 } }
        .transcript { margin-top:12px; max-height:220px; overflow:auto; padding:10px; background: rgba(0,0,0,0.18); border-radius:6px; }
        .transcript-item { margin-bottom:10px; padding:8px; border-left:3px solid #fdbb2d; background: rgba(255,255,255,0.03); }
        .original { font-weight:700; margin-bottom:6px; color:#fff; }
        .translated { color:#fdbb2d; }
        .language-selector { display:flex; gap:8px; margin-bottom:10px; }
        select { flex:1; padding:8px; border-radius:6px; border:none; background: rgba(255,255,255,0.9); color:#000; }
        .warning { margin-top:8px; padding:10px; border-radius:6px; background: rgba(255,0,0,0.12); border-left:4px solid #ff4444; }
        /* Electron 来源选择 overlay */
        .overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); display: none; align-items: center; justify-content: center; z-index: 9999; }
        .picker { background: #1f1f1f; border-radius: 10px; width: min(1000px, 92vw); max-height: 80vh; padding: 16px; overflow: auto; color:#fff; }
        .picker h3 { margin-bottom:8px; color:#fdbb2d; }
        .sources { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; }
        .source-item { background:#222; padding:8px; border-radius:8px; cursor:pointer; border:1px solid #333; transition: transform .15s; }
        .source-item:hover { transform: translateY(-2px); }
        .thumb { width: 100%; height: 110px; background:#444; border-radius:6px; object-fit: cover; margin-bottom: 8px; display:block; }
        .source-name { font-size:0.9rem; color:#ddd; word-break: break-all; }
        .picker-actions { display:flex; justify-content:flex-end; margin-top:10px; }
    </style>
    <script>
        console.log('🔧 mio.html 开始执行');
        console.log('📍 当前 URL:', window.location.href);
        console.log('🌐 是否在 Electron 中:', !!window.electronAPI);

        // 立即检查 electronAPI 的详细结构
        setTimeout(() => {
            if (window.electronAPI) {
                console.log('📋 electronAPI 完整结构:');
                console.dir(window.electronAPI);

                if (window.electronAPI.desktopCapturer) {
                    console.log('🎯 desktopCapturer 方法:', Object.keys(window.electronAPI.desktopCapturer));
                }
            } else {
                console.warn('❌ window.electronAPI 不存在');
            }
        }, 1000);
    </script>
</head>
<body>
<div class="container">
    <div class="content">
        <div class="panel">
            <h2>音频捕捉控制</h2>
            <div class="audio-guide">
                <p>请在您的电脑上打开任何正在播放音频的页面或应用程序（如视频网站、音乐播放器等），然后点击下方按钮开始捕获声音。</p>
            </div>

            <div class="audio-viz-wrap">
                <canvas id="audioCanvas"></canvas>
            </div>

            <div class="controls">
                <button id="startCapture">开始捕捉声音</button>
                <button id="stopCapture" disabled>停止捕捉</button>
            </div>

            <div class="status" id="captureStatus">点击"开始捕捉声音"按钮，选择要捕捉的窗口或屏幕。</div>
            <div class="recording-indicator" id="recordingIndicator" style="display:none;"><span class="pulse"></span> 正在捕捉音频...</div>

            <div class="warning">
                - 点击开始捕获后可在列表中选择要捕捉的窗口/屏幕。<br>
                - 请确保目标窗口正在播放音频。<br>
                - 在选择窗口时，请勾选"共享音频"选项以确保捕获声音。
            </div>
        </div>

        <div class="panel">
            <h2>翻译结果</h2>
            <div class="language-selector">
                <select id="sourceLang">
                    <option value="auto" selected>自动检测</option>
                    <option value="en">英语</option>
                    <option value="zh">中文</option>
                    <option value="ja">日语</option>
                    <option value="ko">韩语</option>
                    <option value="fr">法语</option>
                    <option value="es">西班牙语</option>
                </select>
                <select id="targetLang">
                    <option value="zh">中文</option>
                    <option value="en">英语</option>
                    <option value="ja">日语</option>
                    <option value="ko">韩语</option>
                    <option value="fr">法语</option>
                    <option value="es">西班牙语</option>
                </select>
            </div>

            <div class="transcript" id="transcriptContainer">
                <div class="transcript-item">
                    <div class="original">系统准备就绪，可直接开始捕捉声音。</div>
                    <div class="translated">The system is ready, you can start capturing sound directly.</div>
                </div>
            </div>

            <div class="status" id="translationStatus">等待翻译内容...</div>
        </div>
    </div>

    <div class="panel">
        <h3>使用说明</h3>
        <ol>
            <li><strong>准备音频源</strong>：在您的电脑上打开任何播放音频的页面或应用程序</li>
            <li><strong>开始捕获</strong>：点击"开始捕捉声音"按钮，选择正在播放音频的窗口或屏幕</li>
            <li><strong>查看结果</strong>：音频波形显示在下方，转录结果会实时显示在右侧面板</li>
        </ol>
    </div>
</div>

<!-- Electron 来源选择器 -->
<div class="overlay" id="sourceOverlay">
    <div class="picker">
        <h3>选择要捕捉的窗口或屏幕</h3>
        <div class="sources" id="sourceList"></div>
        <div class="picker-actions"><button id="cancelOverlay">取消</button></div>
    </div>
</div>
<script>
    // 在 mio.html 的 script 开头添加
    (function() {
        console.log('🔧 检查媒体设备兼容性...');

        // 确保 mediaDevices 存在
        if (!navigator.mediaDevices) {
            console.warn('⚠️ navigator.mediaDevices 不存在，尝试 polyfill');
            navigator.mediaDevices = {};
        }

        // 检查 getUserMedia 支持
        if (!navigator.mediaDevices.getUserMedia) {
            // 尝试使用前缀版本
            const getUserMedia = navigator.getUserMedia ||
                navigator.webkitGetUserMedia ||
                navigator.mozGetUserMedia ||
                navigator.msGetUserMedia;

            if (getUserMedia) {
                console.log('✅ 使用前缀版本的 getUserMedia');
                navigator.mediaDevices.getUserMedia = function(constraints) {
                    return new Promise((resolve, reject) => {
                        getUserMedia.call(navigator, constraints, resolve, reject);
                    });
                };
            } else {
                console.error('❌ 浏览器不支持 getUserMedia');
                // 创建模拟的 getUserMedia 用于测试
                navigator.mediaDevices.getUserMedia = function(constraints) {
                    return Promise.reject(new Error('getUserMedia not supported in this environment'));
                };
            }
        }

        // 检查 getDisplayMedia 支持
        if (!navigator.mediaDevices.getDisplayMedia) {
            const getDisplayMedia = navigator.getDisplayMedia ||
                navigator.webkitGetDisplayMedia ||
                navigator.mozGetDisplayMedia;

            if (getDisplayMedia) {
                console.log('✅ 使用前缀版本的 getDisplayMedia');
                navigator.mediaDevices.getDisplayMedia = function(constraints) {
                    return new Promise((resolve, reject) => {
                        getDisplayMedia.call(navigator, constraints, resolve, reject);
                    });
                };
            } else {
                console.warn('⚠️ getDisplayMedia 不可用，将使用备用方案');
            }
        }

        console.log('✅ 媒体设备兼容性检查完成');
    })();
</script>

<script>
    (function() {
        // 等待 electronAPI 加载完成的函数
        function waitForElectronAPI() {
            return new Promise((resolve) => {
                const maxTries = 50;
                let tries = 0;

                const check = () => {
                    tries++;

                    // 检查多种可能的 API 结构
                    const api = window.electronAPI;
                    if (api) {
                        // 检查 desktopCapturer.getSources
                        if (api.desktopCapturer && typeof api.desktopCapturer.getSources === 'function') {
                            console.log('[mio] 检测到 electronAPI.desktopCapturer.getSources');
                            resolve(true);
                            return;
                        }
                        // 检查顶级的 getSources
                        else if (typeof api.getSources === 'function') {
                            console.log('[mio] 检测到 electronAPI.getSources');
                            resolve(true);
                            return;
                        }
                        // 检查其他可能的结构
                        else if (api.desktop && typeof api.desktop.getSources === 'function') {
                            console.log('[mio] 检测到 electronAPI.desktop.getSources');
                            resolve(true);
                            return;
                        }
                    }

                    if (tries >= maxTries) {
                        console.warn('[mio] 超时未检测到有效的 electronAPI');
                        console.warn('[mio] 当前 electronAPI:', api ? Object.keys(api) : 'undefined');
                        if (api && api.desktopCapturer) {
                            console.warn('[mio] desktopCapturer 方法:', Object.keys(api.desktopCapturer));
                        }
                        resolve(false);
                    } else {
                        setTimeout(check, 100);
                    }
                };

                check();
            });
        }

        // 初始化函数，等待API就绪后执行
        async function init() {
            // 检测环境
            const isLocalhost = window.location.hostname === 'localhost' ||
                window.location.hostname === '127.0.0.1' ||
                window.location.hostname === '';

            const isSecure = window.location.protocol === 'https:';
            console.log('🌍 环境检测:', {
                hostname: window.location.hostname,
                protocol: window.location.protocol,
                isLocalhost,
                isSecure,
            });

            // 根据环境调整策略
            if (!isSecure && !isLocalhost) {
                console.warn('⚠️ 非安全上下文，媒体功能可能受限');
                // 可以在这里添加用户提示
            }
            // 等待 electronAPI 加载完成
            const isElectron = await waitForElectronAPI();
            console.log('[mio] 最终检测到 Electron 环境:', isElectron);

            // DOM 元素
            const startCaptureBtn = document.getElementById('startCapture');
            const stopCaptureBtn = document.getElementById('stopCapture');
            const captureStatus = document.getElementById('captureStatus');
            const recordingIndicator = document.getElementById('recordingIndicator');
            const audioCanvas = document.getElementById('audioCanvas');

            const sourceOverlay = document.getElementById('sourceOverlay');
            const sourceList = document.getElementById('sourceList');
            const cancelOverlayBtn = document.getElementById('cancelOverlay');

            const transcriptContainer = document.getElementById('transcriptContainer');
            const translationStatus = document.getElementById('translationStatus');
            const sourceLang = document.getElementById('sourceLang');
            const targetLang = document.getElementById('targetLang');

            // 状态变量
            let displayStream = null;
            let audioCtx = null, analyser = null, sourceNode = null, animationId = null, dataArray = null, bufferLength = 0;
            let fakeInterval = null, transcriptIndex = 0;

            // 示例翻译数据
            const sampleTranscripts = [
                { original: "Hello, welcome to our video presentation.", translated: "你好，欢迎观看我们的视频演示。" },
                { original: "Today we will discuss the latest technology trends.", translated: "今天我们将讨论最新的技术趋势。" },
                { original: "Artificial intelligence is transforming many industries.", translated: "人工智能正在改变许多行业。" },
                { original: "Machine learning algorithms are becoming more sophisticated.", translated: "机器学习算法正变得越来越复杂。" },
                { original: "Thank you for watching this presentation.", translated: "感谢您观看本次演示。" }
            ];

            // 直接开始捕获，无需先加载URL
            captureStatus.textContent = '请确保您的电脑上有正在播放音频的窗口或应用程序，然后点击下方按钮开始捕获声音。';

            // 开始捕捉 - 可以直接点击，无需先加载URL
            startCaptureBtn.addEventListener('click', async () => {
                startCaptureBtn.disabled = true;
                stopCaptureBtn.disabled = false;
                recordingIndicator.style.display = 'flex';

                if (isElectron) {
                    try {
                        console.log('[mio] 使用 Electron 捕获模式');
                        await startCaptureElectron();
                        return;
                    } catch (e) {
                        const errorMsg = e && e.message ? e.message : String(e);
                        captureStatus.textContent = '捕获失败，回退到浏览器方式：' + errorMsg;
                        console.error('[mio] Electron 捕获失败:', e);
                    }
                }

                try {
                    console.log('[mio] 使用浏览器捕获模式');
                    await startCaptureBrowser();
                } catch (err) {
                    const msg = err && err.message ? err.message : String(err);
                    captureStatus.textContent = '浏览器捕捉失败：' + msg;
                    console.error('[mio] 浏览器捕获失败:', err);
                    startFakeTranscripts();
                }
            });

            // 停止捕捉
            stopCaptureBtn.addEventListener('click', () => {
                stopAllCapture();
            });

            // Electron 捕获逻辑
            async function startCaptureElectron() {
                console.log('[mio] 开始 Electron 捕获流程');
                console.log('[mio] electronAPI 状态:', window.electronAPI ? '存在' : '不存在');

                if (window.electronAPI) {
                    console.log('[mio] electronAPI 方法:', Object.keys(window.electronAPI));
                    if (window.electronAPI.desktopCapturer) {
                        console.log('[mio] desktopCapturer 方法:', Object.keys(window.electronAPI.desktopCapturer));
                    }
                }

                // 尝试多种调用方式
                let getSourcesFunction;

                if (window.electronAPI?.desktopCapturer?.getSources) {
                    console.log('[mio] 使用 desktopCapturer.getSources');
                    getSourcesFunction = (options) => window.electronAPI.desktopCapturer.getSources(options);
                }
                else if (window.electronAPI?.getSources) {
                    console.log('[mio] 使用顶级的 getSources');
                    getSourcesFunction = (options) => window.electronAPI.getSources(options);
                }
                else {
                    captureStatus.textContent = '错误：未找到 getSources 方法';
                    console.error('[mio] getSources 方法不存在');
                    return;
                }

                if (!getSourcesFunction) {
                    captureStatus.textContent = '错误：无法确定 getSources 方法';
                    return;
                }
                captureStatus.textContent = '正在获取窗口列表...';
                sourceList.innerHTML = '<div style="color:#ccc;padding:8px">正在获取来源...</div>';
                sourceOverlay.style.display = 'flex';

                try {
                    // 调用 electronAPI 获取桌面来源
                    const sources = await window.electronAPI.getSources({
                        types: ['window', 'screen'],
                        thumbnailSize: { width: 320, height: 200 }
                    });

                    console.log('[mio] 从主进程获取到桌面来源，数量:', sources.length);

                    if (!sources || !sources.length) {
                        sourceList.innerHTML = '<div style="color:#ff4444;padding:8px">未获取到任何窗口/屏幕，请确认有其他窗口打开</div>';
                        return;
                    }

                    // 显示手动选择列表
                    sourceList.innerHTML = '';
                    sources.forEach(s => {
                        const item = document.createElement('div');
                        item.className = 'source-item';
                        const thumbSrc = s.thumbnail || '';
                        item.innerHTML = `<img class="thumb" src="${thumbSrc}" alt="窗口预览: ${s.name}"><div class="source-name">${escapeHtml(s.name)}</div>`;
                        item.addEventListener('click', async () => {
                            sourceOverlay.style.display = 'none';
                            await startCaptureWithSource(s);
                        });
                        sourceList.appendChild(item);
                    });

                } catch (error) {
                    // 显示错误信息
                    const errorMsg = error.message || '未知错误';
                    sourceList.innerHTML = `<div style="color:#ff4444;padding:8px">获取来源失败：${errorMsg}</div>`;
                    captureStatus.textContent = '获取来源失败：' + errorMsg;
                    console.error('[mio] 获取桌面来源错误:', error);
                }
            }

            // 取消选择
            cancelOverlayBtn.addEventListener('click', () => {
                sourceOverlay.style.display = 'none';
                startCaptureBtn.disabled = false;
                stopCaptureBtn.disabled = true;
                captureStatus.textContent = '已取消选择来源。请确保您的电脑上有正在播放音频的窗口，然后点击"开始捕捉声音"按钮。';
            });

            // 使用选中的来源开始捕获
            async function startCaptureWithSource(source) {
                captureStatus.textContent = '正在捕捉：' + source.name;
                console.log('[mio] 开始捕捉来源:', source.name, 'ID:', source.id);

                try {
                    const constraints = {
                        audio: {
                            mandatory: {
                                chromeMediaSource: 'desktop',
                                chromeMediaSourceId: source.id
                            }
                        },
                        video: {
                            mandatory: {
                                chromeMediaSource: 'desktop',
                                chromeMediaSourceId: source.id
                            }
                        }
                    };

                    const stream = await navigator.mediaDevices.getUserMedia(constraints);
                    const audioTracks = stream.getAudioTracks();

                    if (!audioTracks || audioTracks.length === 0) {
                        captureStatus.textContent = '未检测到音频轨（来源可能不含音频）';
                        stream.getTracks().forEach(t=>t.stop());
                        startFakeTranscripts();
                        return;
                    }

                    displayStream = stream;
                    audioTracks[0].onended = () => {
                        console.log('[mio] 音频轨道已结束');
                        stopAllCapture();
                    };

                    initAudioVisualization(stream);
                    captureStatus.textContent = `正在捕捉 ${source.name} 的音频。`;
                    startFakeTranscripts();

                } catch (error) {
                    const errorMsg = error.message || '未知错误';
                    captureStatus.textContent = `捕捉 ${source.name} 失败：${errorMsg}`;
                    console.error('[mio] 捕捉来源失败:', error);
                    startFakeTranscripts();
                }
            }

            // 浏览器捕获逻辑
            async function startCaptureBrowser() {
                console.log('🌐 开始浏览器捕获模式');
                captureStatus.textContent = '请在系统选择器中选择要捕捉的窗口或屏幕，并勾选"共享音频"。';

                try {
                    // 检查 getDisplayMedia 是否可用
                    if (!navigator.mediaDevices.getDisplayMedia) {
                        throw new Error('getDisplayMedia 不可用');
                    }

                    const stream = await navigator.mediaDevices.getDisplayMedia({
                        video: true,
                        audio: true
                    }).catch(error => {
                        console.error('❌ getDisplayMedia 错误:', error);
                        // 备用方案：尝试使用 Electron 桌面捕获
                        if (window.electronAPI) {
                            captureStatus.textContent = '浏览器捕获失败，尝试使用捕获...';
                            return startCaptureElectron();
                        }
                        throw error;
                    });

                    const audioTracks = stream.getAudioTracks();
                    if (!audioTracks || audioTracks.length === 0) {
                        captureStatus.textContent = '未检测到音频轨，请在共享对话框中勾选"共享音频"。';
                        stream.getTracks().forEach(t => t.stop());
                        startFakeTranscripts();
                        return;
                    }

                    displayStream = stream;
                    audioTracks[0].onended = () => stopAllCapture();
                    initAudioVisualization(stream);
                    captureStatus.textContent = '正在捕捉（浏览器模式）。';
                    startFakeTranscripts();

                } catch (err) {
                    console.error('❌ 浏览器捕获错误:', err);

                    // 如果是在 Electron 环境中，尝试使用桌面捕获
                    if (window.electronAPI) {
                        captureStatus.textContent = '浏览器捕获失败，尝试使用桌面捕获...';
                        await startCaptureElectron();
                    } else {
                        // 纯浏览器环境，启用模拟模式
                        captureStatus.textContent = '捕获失败，启用模拟演示模式。';
                        startFakeTranscripts();
                    }
                }
            }

            // 停止所有捕获
            function stopAllCapture() {
                try {
                    if (displayStream) {
                        displayStream.getTracks().forEach(t=>t.stop());
                        console.log('[mio] 已停止所有媒体轨道');
                    }
                } catch(e) {
                    console.error('[mio] 停止媒体轨道失败:', e);
                }

                displayStream = null;
                stopAudioVisualization();

                if (fakeInterval) {
                    clearInterval(fakeInterval);
                    fakeInterval = null;
                    console.log('[mio] 已停止模拟转录');
                }

                startCaptureBtn.disabled = false;
                stopCaptureBtn.disabled = true;
                recordingIndicator.style.display = 'none';
                captureStatus.textContent = '音频捕捉已停止';
            }

            // 模拟转录
            function startFakeTranscripts() {
                if (fakeInterval) clearInterval(fakeInterval);
                transcriptIndex = 0;
                transcriptContainer.innerHTML = '';
                fakeInterval = setInterval(() => {
                    const t = sampleTranscripts[transcriptIndex % sampleTranscripts.length];
                    addTranscriptItem(t.original, t.translated);
                    transcriptIndex++;
                }, 3000);
                console.log('[mio] 已开始模拟转录');
            }

            // 添加转录项
            function addTranscriptItem(original, translated) {
                const item = document.createElement('div');
                item.className = 'transcript-item';
                item.innerHTML = `<div class="original">${escapeHtml(original)}</div><div class="translated">${escapeHtml(translated)}</div>`;
                transcriptContainer.appendChild(item);
                transcriptContainer.scrollTop = transcriptContainer.scrollHeight;
                translationStatus.textContent = `已翻译: ${original.substring(0,30)}...`;
            }

            // 音频可视化
            function initAudioVisualization(stream) {
                try {
                    if (audioCtx) {
                        try { audioCtx.close(); }
                        catch(e) { console.error('[mio] 关闭AudioContext失败:', e); }
                    }

                    audioCtx = new (window.AudioContext || window.webkitAudioContext)();
                    sourceNode = audioCtx.createMediaStreamSource(stream);
                    analyser = audioCtx.createAnalyser();
                    analyser.fftSize = 2048;
                    bufferLength = analyser.fftSize;
                    dataArray = new Uint8Array(bufferLength);
                    sourceNode.connect(analyser);
                    resizeCanvasToDisplaySize(audioCanvas);
                    drawVisualizer();
                    console.log('[mio] 音频可视化初始化完成');

                } catch (e) {
                    const errorMsg = e.message || '未知错误';
                    captureStatus.textContent = '可视化初始化失败：' + errorMsg;
                    console.error('[mio] 音频可视化初始化失败:', e);
                }
            }

            // 绘制可视化效果
            function drawVisualizer() {
                const canvas = audioCanvas;
                const ctx = canvas.getContext('2d');
                const width = canvas.width, height = canvas.height;

                function draw() {
                    animationId = requestAnimationFrame(draw);
                    analyser.getByteTimeDomainData(dataArray);

                    ctx.fillStyle = '#0b0b0b';
                    ctx.fillRect(0, 0, width, height);

                    ctx.lineWidth = 2;
                    ctx.strokeStyle = '#fdbb2d';
                    ctx.beginPath();

                    const sliceWidth = width / bufferLength;
                    let x = 0;

                    for (let i = 0; i < bufferLength; i++) {
                        const v = dataArray[i] / 128.0;
                        const y = v * height / 2;
                        if (i === 0) ctx.moveTo(x, y);
                        else ctx.lineTo(x, y);
                        x += sliceWidth;
                    }

                    ctx.lineTo(width, height / 2);
                    ctx.stroke();

                    // 绘制RMS条
                    let sum = 0;
                    for (let i = 0; i < bufferLength; i++) {
                        const v = (dataArray[i] - 128) / 128;
                        sum += v * v;
                    }
                    const rms = Math.sqrt(sum / bufferLength);
                    const barW = Math.max(2, Math.min(width, rms * width * 1.6));
                    ctx.fillStyle = 'rgba(255,187,45,0.25)';
                    ctx.fillRect(0, height - 8, barW, 6);
                }

                draw();
            }

            // 停止音频可视化
            function stopAudioVisualization() {
                try {
                    if (animationId) cancelAnimationFrame(animationId);
                } catch(e) {
                    console.error('[mio] 取消动画帧失败:', e);
                }

                animationId = null;

                try {
                    if (analyser) analyser.disconnect();
                    if (sourceNode) sourceNode.disconnect();
                    if (audioCtx) audioCtx.close();
                } catch(e) {
                    console.error('[mio] 断开音频节点失败:', e);
                }

                analyser = null;
                sourceNode = null;
                audioCtx = null;
                dataArray = null;
                bufferLength = 0;

                if (audioCanvas && audioCanvas.getContext) {
                    const ctx = audioCanvas.getContext('2d');
                    ctx.clearRect(0, 0, audioCanvas.width, audioCanvas.height);
                }

                console.log('[mio] 音频可视化已停止');
            }

            // 调整Canvas大小
            function resizeCanvasToDisplaySize(canvas) {
                const rect = canvas.getBoundingClientRect();
                const dpr = window.devicePixelRatio || 1;
                const w = Math.round(rect.width * dpr);
                const h = Math.round(rect.height * dpr);
                if (canvas.width !== w || canvas.height !== h) {
                    canvas.width = w;
                    canvas.height = h;
                }
            }

            // 语言选择变化
            sourceLang.addEventListener('change', () => {
                translationStatus.textContent = '语言设置已更新';
            });
            targetLang.addEventListener('change', () => {
                translationStatus.textContent = '语言设置已更新';
            });

            // HTML转义
            function escapeHtml(s) {
                return String(s).replace(/[&<>"'`=\/]/g, c => ({
                    '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;',
                    "'":'&#39;', '/':'&#x2F;', '`':'&#x60;', '=':'&#x3D;'
                }[c]));
            }

            // 初始化状态
            startCaptureBtn.disabled = false; // 直接启用开始捕捉按钮
            stopCaptureBtn.disabled = true;
            window.addEventListener('resize', () => {
                try { resizeCanvasToDisplaySize(audioCanvas); }
                catch(e) { console.error('[mio] 调整Canvas大小失败:', e); }
            });

            console.log('[mio] 页面初始化完成');
        }

        // 启动初始化流程
        init();
    })();
</script>
</body>
</html>